// 把data中的数据， 都用Object.defineProperty重新定义 es5
// Object.defineProperty 不能兼容ie8及其以下， 所以vue无法兼容ie8版本
import { isObject, def } from "../utils/index.js"
import { arrayMethods } from "./array.js";
import Dep from "./dep.js";
class Observer {
  constructor(data) {
    // value.__ob__ = this; // 给每个监控对象都增加一个__ob__属性
    def(data, "__ob__", this); // 给每个监控对象都增加一个__ob__属性
    // 首先判断值是不是数组
    if (Array.isArray(data)) {
      // 如果是数组的话， 并不会对索引进行观测， 因为会导致性能问题
      // 前端开发中， 会很少很少 的去操作索引： push unshift shift
      data.__proto__ = arrayMethods;
      // 如果数组中放的是对象， 我再检测
      this.observerArray(data);
    } else {
      // vue如果数据的层次过多， 需要递归的去解析对象中的属性， 依次增加set和get方法
      this.walk(data);
    }
  }


  observerArray(data) {
    // 优化数组
    let i = 0;
    for (; i < data.length; i++) {
      observe(data[i])
    }
  }

  // 1. 处理基础值
  // 2. 处理对象
  // 3. 优化数组
  walk(data) {
    let keys = Object.keys(data);
    let i = 0;
    for (; i < keys.length; i++) {
      let key = keys[i], value = data[key];
      defineReactive(data, key, value); // 定义响应式
    }
  }
}

function defineReactive(data, key, value) {
  let dep = new Dep();
  observe(value); // 递归实现深度检测
  Object.defineProperty(data, key, {
    configurable: true,
    enumerable: true,
    get() { // 获取值的时候，进行一些操作
      // 每个属性都对应着自己的watcher
      if (Dep.target) {
        dep.depend(); // 意味中我要将watcher存起来
      }
      return value;
    },
    set(newValue) {
      if (newValue === value) return;
      console.log("值发生了改变");
      observe(newValue);
      value = newValue;
      dep.notify(); // 通知依赖的watcher来进行一个更新操作
    }
  })
}

export function observe(data) {
  if (isObject(data)) return;

  return new Observer(data);
}